|
Apelon, Inc. |
Phone: (203) 431-2530 |
Apelon
Distributed Terminology System (DTS) DTS Editor Plug-ins Guide |
Getting a Menu, Menu Items and Toolbar
Creating a GUI for the Plug-in Module
Establishing Drag and Drop Interoperability with other DTS
Editor features
The DTS Editor Plug-in Framework, introduced with DTS Version 3.4, provides a framework for customizing or extending the capabilities of the DTS Editor. Using the Plug-in Framework, developers may create new plug-in ‘modules’ designed to interface and work with existing DTS Editor features. This provides the DTS developer the ability to provide targeted, custom functionality without having to spend time and effort developing a GUI and the supporting DTS connection framework.
A plug-in is recognized by the DTS Editor by extending the DTSEditorModule class in a recognized package. Plug-ins import the classes in the apelon.apps.dts.editor.modules package to gain access to Editor services. Each plug-ins overrides the DTSEditorModule classes initModule() method. This method is called by the DTS Editor at start-up and provides the plug-in with a copy of the DTSEditorModuleMgr class. Custom initialization code may also be placed in this method. Additional methods are available for the plug-in to implement which are called by the Editor to initialize custom toolbar and menu items.
Beyond the basic requirements for recognizing and initializing a plug-in, a GUI can also be created. The DTSEditorModuleMgr class provides functionality for generating stand-alone panels and panes that may be displayed within the Editor. Drag and drop support is available for DTS data objects such as Concept, Property, Term, etc. A plug-in can also listen for and handle Editor connection and editing events. Methods for handling exceptions and showing error messages are also available.
This tutorial will take walk through the process of creating a DTS Editor plug-in. The example is called “SimplePlugIn”.
The SimplePlugIn code can be found in your DTS installation at the following path:
samples\editorplugin\src\com\apelon\modules\dts\editor\simpleplugin
Plug-in modules must fulfill the following two conditions to be recognized as plug-ins by the DTS Editor.
1. The plug-in extends the DTSEditorModule class.
2. The plug-ins java class files must reside in a package recognized by the DTS Editor.
The DTS Editor must be aware that a custom plug-in module exists for it to load the plug-in and make it available through the Editor. To achieve this, the java class extending DTSEditorModule needs to be in a specific location. The DTS Editor will automatically recognize any valid plug-in created in com.apelon.modules.dts.editor or any subpackage (com.apelon.modules.dts.editor.*). The DTS Editor will also search any packages specified as modulePackageName1…n in the dtseditor.xml file.
Example
modulePackageName1 = com.mycompany.my.dts.plugin
com.apelon.modules.dts.editor.*
The DTS Editor will search packages in the following order:
modulePackageName1…n
com.apelon.modules.dts.editor
com.apelon.modules.dts.editor.*
A DTS plug-in needs to import com.apelon.apps.dts.editor.modules package. This package contains the following classes which provide fields and methods that provide access to DTS Editor functionality:
The SimplePlugIn example also imports classes in com.apelon.beans.dts.plugin.connection which manage events related to DTS connection objects.
Import Example
// Apelon
Imports
import
com.apelon.apps.dts.editor.modules.*;
import
com.apelon.beans.dts.plugin.connection.DtsConnectionListener;
import
com.apelon.beans.dts.plugin.connection.DtsConnectionEvent;
import
com.apelon.beans.dts.plugin.connection.ConnectionCloseVeto;
As stated, DTSEditorModule should be extended to create a custom plug-in for the Apelon DTS Editor. The extending class must have a no parameter constructor or the class won't be recognized as a plug-in.
The DTSEditorModule module extension classes in com.apelon.modules.dts.editor or a subpackage are loaded by the DTS Editor. Classes residing in other packages must be specified in the DTS Editor property file (bin/editor/dtseditor.xml) as follows:
A module is loaded during DTSEditor startup. The sequence of actions are :
Additionally, DtsConnectionListener needs to be implemented in order to handle events related to DTS Server and database connections.
Class
Declaration Code
public class SimplePlugIn extends DTSEditorModule implements
DtsConnectionListener
As stated previously, plug-ins need to implement initModule(). This method is called by the DTS Editor at start-up and serves two purposes.
1. Provides the plug-in with a copy of the DTSEditorModuleMgr class.
The copy of the DTSEditorModuleMgr class is the custom plug-ins interface with the exposed functionality of the DTS Editor. The following steps occur in the initModule() implementation in the SimplePlugIn example:
Module Initialization
Code
DTSEditorModuleMgr
moduleMgr;
public void
initModule(DTSEditorModuleMgr mgr) {
// Initialize our local instance of the
Module Manager
this.moduleMgr = mgr;
// Register ourselves as a connection
listener
this.moduleMgr.registerConnectionListener(this);
// Initialize panel settings
initModulePanels();
}
After calling the initModule method the DTS Editor looks to see if a module is to be accessible using custom menu and/or toolbar entries.
A module may provide for direct user access from the DTS Editor in three ways.
3. Custom DTS Editor toolbar button (getModuleToolbarItems ())
Action listeners need to be added to each menu and toolbar item in this code to provide the functionality you want your plug-in to offer.
getModuleMenus()
returns a new main menu to be displayed on the DTS Editor menu bar. This menu
will be placed to the left of the Help menu.
Menu Code
public JMenu[]
getModuleMenus (){
JMenu editMenu = new JMenu("Simple
Plugin Edit");
editMenu.add(getModuleMenuItem1());
editMenu.add(getModuleMenuItem2());
JMenu[] menus = new JMenu[] {editMenu};
return menus;
}
If you want to add menu items to an existing DTSEditor menu then override getModuleMenuItems()
Menu Item Code
public
JMenuItem[] getModuleMenuItems(int group) {
// Create an empty array of JMenuItems to
hold our custom items
JMenuItem[] menuItems = new JMenuItem[0];
// Create a list for the desired menu group
switch (group) {
case TOOLS_MENU_ITEMS:
menuItems = new JMenuItem[]
{getSimplePlugInMenuItem(), getSimplePlugInCfgMenuItem()};
break;
case HELP_MENU_ITEMS:
menuItems = new JMenuItem[]
{getSimplePluginHelpMenuItem()};
break;
default:
break;
}
return menuItems;
}
The DTS Editor then looks to getModuleToolbarItems() for an array of JButtons that may have custom icons to be displayed in it’s toolbar.
Toolbar Code
public
JComponent[] getModuleToolbarItems() {
Class c = SimplePlugIn.class;
ImageIcon ic;
URL url =
c.getResource("apelicon16.gif");
toolbarImage = new ImageIcon(url,
"GIF");
if (toolbarButton == null) {
toolbarButton = new JButton();
toolbarButton.setIcon(toolbarImage);
toolbarButton.setMargin(new Insets(4, 2, 4,
4));
toolbarButton.setToolTipText("DTS
Editor Simple Plug-in");
toolbarButton.addActionListener(new
ActionListener() {
public void actionPerformed(ActionEvent
e) {
actionPerformed_SimplePluginMenuItem(e);
}
});
toolbarButton.setEnabled(false);
}
return toolbarButton;
}
A
plug-in may need to respond to the DTS Editor’s server connection events. If so, it must register as a
DtsConnectionListener. This provides the
plug-in with the ability to take specific actions if the DTS Editor connects or
disconnects from the DTS Server. These
actions can include enabling or disabling menu items or ensuring proper
handling of connection dependent operations.
The SimplePlugIn code shows an example of the former.
Connection
Event Handling Code
public void
connectionOpened(DtsConnectionEvent event) {
getSimplePlugInMenuItem().setEnabled(true);
getSimplePluginToolbarItem().setEnabled(true);
getModuleMenuItem1().setEnabled(true);
getModuleMenuItem2().setEnabled(true);
getSimplePlugInPanel().addListeners();
}
public void
connectionClosed(DtsConnectionEvent event) {
getSimplePlugInMenuItem().setEnabled(false);
getSimplePluginToolbarItem().setEnabled(false);
getModuleMenuItem1().setEnabled(false);
getModuleMenuItem2().setEnabled(false);
}
A plug-in module needs to implement initModule(). If there is a GUI the module should provide access by implementing getModuleMenus() and/or getModuleToolbarItems(). To allow for handling any conditions arising from connection events it needs to register as a DtsConnectionListener.
The next step is to design and implement functionality that the plug-in is going to provide!
Although not required, a custom plug-in is likely to be GUI based. This will require the definition of one or more panels that will be the user access point to the plug-ins functionality. To define the modules functionality these panels may incorporate calls to the DTS API. The placement and access to these panels is handled via the copy of the DTSEditorModuleMgr class which was passed to the plug-in when the DTS Editor made the call to the initModule() method. In the SimplePlugIn example, a floating panel is displayed when the SimplePlugin menu item is selected.
private void actionPerformed_SimplePluginMenuItem(ActionEvent e) {
fSimplePluginPanel = new
SimplePlugInPanel(this.moduleMgr, getDTSModuleConfig());
fSimplePluginPanel.configure();
JDialog dialog =
this.moduleMgr.createDialog(fSimplePluginPanel, "Simple Plug-in");
WindowListener wndCloser =
new WindowAdapter() {
public void
windowClosing(WindowEvent e) {
fSimplePluginPanel.removeListeners();
}
};
dialog.addWindowListener(wndCloser);
dialog.setModal(false);
dialog.show();
}
Plug-in panels can be tabbed panes, popup panels and popup dialogs. The following code sample shows how SimplePlugInPanel is added to the DTS Editor's left pane when the 'Left Tabbed Pane' radio button is clicked.
Left Tabbed Pane Handling Code
void actionPerformed_rbnTabLeft(ActionEvent e) {
JTabbedPane leftPane = fModuleMgr.getLeftTabbedPane();
JTabbedPane rightPane =
fModuleMgr.getRightTabbedPane();
if
(!findPluginPanel(leftPane)) {
leftPane.add("Simple
Plugin Panel", new SimplePlugInPanel(fModuleMgr));
}
removePluginPanel(rightPane);
}
Much of the editing done in the DTS Editor relies on or is facilitated by drag and drop functionality. Support for drag and drop capability between existing DTS panels and a custom plug-in or between different custom plug-in panels can greatly enhance the capabilities of each.
Various DTS objects can be dragged and dropped between the DTS Editor and a plug-in. These include Concept Association, Concept, Property, Role, Subset, Synonym, Term Association and Term. Each of these has a corresponding Transferable object such as ConceptTransferable, TermTransferable, etc. In turn, each of these Transferable objects contain certain DataFlavors that can be retrieved once the object is dropped. For instance, if a ConceptAssociationTransferable is dropped, a Concept Association, DTS Concept or String object can be obtained and used in the plug-in.
The developer needs to use all the standard java.awt.dnd objects and handling:
1. Create
a default DragSource and a new DragGestureRecognizer.
Drag Source
Code
DragSource dragSource = DragSource.getDefaultDragSource();
dragSource.createDefaultDragGestureRecognizer(subsetTable,
DnDConstants.ACTION_COPY_OR_MOVE, this);
2. Implement the dragGestureRecognized() method of DragGestureListener. The example creates a DTS specific Transferable.
Drag Gesture
Recognized Code
public void dragGestureRecognized(DragGestureEvent dge) {
int selIndex =
subsetTable.getSelectedRow();
if (selIndex == -1) {
return;
}
Subset si = subsetTableModel.getSubsetAt(subsetTableSorter.modelIndex(selIndex));
SubsetTransferable st = new
SubsetTransferable(si);
int colIndex =
subsetTable.getSelectedColumn();
Object obj =
subsetTable.getValueAt(selIndex, colIndex);
if ( obj != null) {
st.setStringValue(obj.toString());
}
dge.startDrag(null, st);
}
3. Instantiate a DropTarget with GUI components that you want to accept drops.
Drop Target Code
private JTextArea getTextArea() {
if (textArea == null) {
textArea = new
JTextArea("Simple PlugIn Panel Text Area \n");
textArea.setEditable(false);
textArea.setPreferredSize(new Dimension(380, 480));
new DropTarget(textArea,
new PanelDropTargetListener());
}
return textArea;
}
4. Handle the drop. SimplePlugInPanel defines a private class called PanelDropTargetListener that extends DropTargetAdapter. This class overrides the methods needed to support drop().
Drop Handling
Code
public void drop(DropTargetDropEvent dtde) {
if (!acceptable) {
dtde.rejectDrop();
return;
}
int dropAction =
dtde.getDropAction();
dtde.acceptDrop(dropAction);
Transferable trans =
dtde.getTransferable();
if (trans == null){
dtde.dropComplete(false);
return;
}
try {
if
(trans.isDataFlavorSupported(DTSMultiTransferable.multiDataFlavor)) {
// Process Multi-Data
Flavor
}
else if
(trans.isDataFlavorSupported(ConceptTransferable.conceptDataFlavor)) {
// Process Concept Data
Flavor
}
else if (trans.isDataFlavorSupported(TermTransferable.termDataFlavor))
{
// Process Term Data
Flavor
}
}
catch (Exception ex) { }
dtde.dropComplete(true);
}
See ‘Objects Supported for Drag and Drop’ in the appendix for reference as to which DTS Editor panels support DND for which DTS data objects.
DTS fires event actions such as ConceptEvent, SubsetEvent, TermEvent, etc. A plug-in can register listeners such as ConceptListener to handle these events. See the com.apelon.dts.client.events package for details.
Register a
Listener
public void addListeners() {
this.dtsModuleMgr.registerConnectionListener(this);
this.dtsModuleMgr.getQueries().getThesaurusQuery().addConceptListener(this);
}
Handling a
Concept Event
public void conceptActionOccurred(ConceptEvent event) {
int eventNum =
event.getEventType();
if (eventNum ==
event.EVENT_TYPE_NEW) {
getTextArea().append("Concept " + event.getConcept().getName()
+ " is added!\n");
} else if (eventNum == event.EVENT_TYPE_MODIFY)
{
getTextArea().append("Concept " + event.getConcept().getName()
+ " is modified!\n");
} else if (eventNum ==
event.EVENT_TYPE_DELETE) {
getTextArea().append("Concept " + event.getConcept().getName()
+ " is deleted!\n");
} else {
getTextArea().append("Invalid event occurred!\n");
}
}
Plug-ins can write error messages to the log file initialized in DTS Editor. A plug-in panel can also display its own popup message dialog by using the DTSEditorModuleMgr showErrorMessage() or handleException() methods. SimplePlugIn contains examples of both.
Error Handling Code
public
SimplePlugInCfgPanel(DTSEditorModuleMgr mgr) {
super();
fModuleMgr = mgr;
try {
initialize();
}
catch (Exception ex) {
String s = "Exception in
SimplePlugInCfgPanel Constructor";
dtsModuleMgr.handleException(s, ex);
fModuleMgr.showErrorMessage("Cannot
load SimplePlugInCfgPanel.");
}
}
Objects Supported for Drag and Drop
Depending on the panel, a single (s) or multiple (m) DTS data object(s) can be dragged or dropped as outlined in the following tables:
Dragging Objects from Editor Components
Table
Drag object |
Ontylog Concept |
DTS Concept |
DTS Role |
DTS Property |
Concept Assoc |
Synonym |
Term |
Term Assoc |
Tree Panel |
m |
m |
m |
|
m |
|
|
|
Concept |
s |
s |
|
|
|
|
|
|
Search Panel |
m |
m |
|
|
|
|
m |
|
Detail Panel |
m |
m |
m |
m |
m |
m |
s |
m |
Association Editor |
s |
s |
|
|
|
|
s |
|
Property Editor |
s |
s |
|
|
|
|
s |
|
Synonym Editor |
|
|
|
|
|
|
|
|
Dropping Objects on Editor Components Table
Drop object |
Ontylog Concept |
DTS Concept |
DTS Role |
DTS Property |
Concept Assoc |
Synonym |
Term |
Term Assoc |
Tree Panel |
s |
s |
s |
|
s |
|
|
|
Concept |
s |
s |
s |
|
s |
|
|
|
Search Panel |
m |
m |
m |
m |
m |
m |
m |
m |
Detail Panel |
s |
s |
s |
|
s |
s |
s |
s |
Association
Editor |
s |
s |
s |
|
s |
s |
s |
s |
Property
Editor |
s |
s |
s |
|
s |
s |
s |
s |
Synonym
Editor |
s |
s |
s |
|
s |
s |
s |
s |
s –
Single drag or drop
m – Multiple drag or drop
Additionally, the various Editor components handle drag and drop in different ways as follows:
Tree Panel – Checks for a drop object. A popup warning message will be shown for an invalid drop object. The valid drop object is DTSConcept. For DTSRole and conceptAssociation the tree panel will get and display their value concepts which are DTSConcept.
Concept Walker Panel – Checks for a drop object. For an invalid drop object there is no warning message and the focus concept combo box remains unchanged. The valid drop object is DTSConcept. For DTSRole and conceptAssociation the concept walker will get and display their value concepts which are DTSConcept.
Search Panel – There is no check for a drop object. It just sets the toString() of the drop object as search text.
Detail Panel - Checks for a drop object. A popup warning message will be shown for an invalid drop object. The valid drop objects are DTSConcept and Term. For DTSRole and conceptAssociation the detail editor will get and display their value concepts which are DTSConcept. For Synonym and TermAssociation the detail editor will get and display their value terms.
Association Editor - Checks for a drop object. There is different handling for “From Concept/Term” and “To Concept/Term” for invalid drop objects.
Property Editor - There is no check for a drop object. If the user drops a DTSProperty to the Concept/Term combo box, the box will go blank.
Synonym Editor - Checks for a drop object. The user can only drop a concept into the Concept combo box and only drop a Term into a Term Combo box. Otherwise, a warning message will pop up. If the user drops a DTSProperty object into the Concept or Term combo box, the combo box will remain unchanged like the concept walker.